#pragma once
#include <memory>
#include <poll.h>
#include "log.hpp"
#include "Sock.hpp"

#define FD_NORM -1
#define nfds_num 100

class TcpServer
{
public:
    TcpServer(const uint16_t port = 8080, nfds_t nfds = nfds_num)
        : _port(port), _nfds(nfds)
    {
        _listensock = Sock::Socket();
        Sock::Bind(_listensock, _port);
        Sock::Listen(_listensock);

        _fds = new struct pollfd[_nfds];
        for (int i = 0; i < _nfds; ++i)
        {
            _fds[i].fd = FD_NORM;
            _fds[i].events = _fds[i].revents = 0;
        }

        _fds[0].fd = _listensock;
        _fds[0].events = POLLIN;

        _timeout = 5000;
    }

    ~TcpServer()
    {
        if (_listensock >= 0)
            close(_listensock);
        if (_fds)
            delete[] _fds;
    }

    void Start()
    {
        while (true)
        {
            DebugPrint();
            int ret = poll(_fds, _nfds, _timeout);
            if (ret < 0)
            {
                logMessage(WARNING, "poll error, %d, %s", errno, strerror(errno));
            }
            else if (ret == 0)
            {
                logMessage(NORMAL, "time out, try again.");
            }
            else
            {
                logMessage(NORMAL, "poll success, get a new link event.");
                HandlerEvent();
            }
        }
    }

private:
    void HandlerEvent()
    {
        for (int i = 0; i < _nfds; ++i)
        {
            if (_fds[i].fd == FD_NORM)
                continue;
            if (_fds[i].revents & POLLIN)
            {
                if (_fds[i].fd == _listensock)
                    Accepter();
                else
                    Recever(i);
            }
        }
    }

    void Accepter()
    {
        std::string client_ip;
        uint16_t client_port;
        int serversock = Sock::Accept(_listensock, &client_ip, &client_port);
        logMessage(NORMAL, "get a new link success.[%s : %d], sock is %d", client_ip.c_str(), client_port, serversock);

        int pos = 1;
        for (; pos < _nfds; ++pos)
        {
            if (_fds[pos].fd == FD_NORM)
            {
                _fds[pos].fd = serversock;
                _fds[pos].events = POLLIN;
                break;
            }
        }
        if (pos == _nfds)
        {
            logMessage(WARNING, "poll full, close: %d", serversock);
            close(serversock);
        }
    }

    void Recever(int pos)
    {
        char readBuffer[1024];
        int ret = recv(_fds[pos].fd, readBuffer, sizeof(readBuffer) - 1, 0);
        if (ret > 0)
        {
            readBuffer[ret] = 0;
            logMessage(NORMAL, "client[%d]#: %s", _fds[pos], readBuffer);
        }
        else if (ret == 0)
        {
            logMessage(NORMAL, "client[%d] quit, server will close its sock.", _fds[pos].fd);
            close(_fds[pos].fd);
            _fds[pos].fd = FD_NORM;
            _fds[pos].events = 0;
        }
        else
        {
            logMessage(WARNING, "%d sock recv error. the errno is %d, %s. ", _fds[pos].fd, errno, strerror(errno));
            close(_fds[pos].fd);
            _fds[pos].fd = FD_NORM;
            _fds[pos].events = 0;
        }
    }

    void DebugPrint()
    {
        std::cout << "_fds[]: ";
        for (int i = 0; i < _nfds; ++i)
        {
            if (_fds[i].fd == FD_NORM)
                continue;
            std::cout << _fds[i].fd << " ";
        }
        std::cout << std::endl;
    }

private:
    int _listensock;
    uint16_t _port;
    struct pollfd *_fds;
    nfds_t _nfds;
    int _timeout;
};